using System;
using System.Collections.Generic;
using System.Text;
using TVDesigner.Entities.Elements;

namespace TVDesigner.Generator.GeneratorEntities
{
    public class ScreenGenerator : GenericComponentGenerator
    {
        private Screen _Screen;
        private List<GenericComponentGenerator> _GenericComponentGenerators;
        private List<HButtonGenerator> _HButtonGeneratorGenerators;

        public ScreenGenerator(Screen screen)
            : base(screen)
        {
            _Screen = screen;
            _GenericComponentGenerators = new List<GenericComponentGenerator>();
            _HButtonGeneratorGenerators = new List<HButtonGenerator>();

            foreach (GenericComponent gc in _Screen.Components)
            {
                GenericComponentGenerator gcg = GenericComponentGeneratorFactory.GetGenerator(gc);
                if (gcg != null)
                {
                    _GenericComponentGenerators.Add(gcg);
                }
                if (gcg is HButtonGenerator)
                {
                    _HButtonGeneratorGenerators.Add(gcg as HButtonGenerator);
                }
            }
        }

        public override string TypeString
        {
            get { return _Screen.NameStartedWithUpperCase; }
        }

        protected override void _SetAttributes(StringBuilder sb)
        {
        }

        public string DeclareClass(string package, string xletName)
        {
            StringBuilder sb = new StringBuilder();

            //package
            if (package != null && !package.Equals(string.Empty))
            {
                sb.Append("package ").Append(package).Append(";\n\n");
            }

            //imports.
            sb.Append("import org.havi.ui.HContainer;\n\n");

            //class declaration.
            sb.Append("public class ").Append(_Screen.NameStartedWithUpperCase).Append(" extends TVDesignerScreen {\n");

            sb.Append("\n");
            //atributes
            _LoadAtributesDeclaration(sb, xletName);
            sb.Append("\n");

            //constructors.
            _LoadConstructor(sb, xletName);
            sb.Append("\n");

            //methods.
            _LoadMethods(sb, xletName);
            sb.Append("\n");

            sb.Append("}\n");

            return sb.ToString();
        }

        private void _LoadAtributesDeclaration(StringBuilder sb, string xletName)
        {
            sb.Append("\tprivate org.havi.ui.HIcon[] focusableButtons;\n");
            sb.Append("\tprivate int count;\n");
            foreach (GenericComponentGenerator gcg in _GenericComponentGenerators)
            {
                sb.Append(gcg.AttributeDeclaration);
            }
        }

        private void _LoadConstructor(StringBuilder sb, string xletName)
        {
            sb.Append("\tpublic ").Append(_Screen.NameStartedWithUpperCase).Append("(").Append(xletName).Append(" xlet) {\n");
            sb.Append("\t\tsuper();\n");
            sb.Append("\t\tthis.xlet = xlet;\n");
            sb.Append("\t\tthis.init();\n");
            sb.Append("\t}\n");
        }

        private void _LoadMethods(StringBuilder sb, string xletName)
        {
            this._LoadInitMethod(sb);
            sb.Append("\n");

            foreach (GenericComponentGenerator gcg in _GenericComponentGenerators)
            {
                sb.Append(gcg.MethodDeclaration);
                sb.Append("\n");
            }

            //TVDesignerScreen interface method.
            this._LoadKeyEventHandlerMethod(sb, xletName);
            sb.Append("\n");
            this._LoadSetXlet(sb, xletName);
            sb.Append("\n");
            this._LoadSetVisible(sb);
        }

        private void _LoadInitMethod(StringBuilder sb)
        {
            sb.AppendLine("\tprotected void init() {");

            //loading the values.
            sb.AppendLine("\t\tthis.setVisible(false);");
            //sb.Append("\t\tthis.setLocation(").Append(this.Location.X).Append(", ").Append(this.Location.Y).Append(");\n");
            sb.AppendLine("\t\tthis.setLocation(0, 0);");
            sb.AppendLine("\t\tthis.setSize(720, 480);");
            //sb.Append("\n");

            if (_Screen.ScreenResize != null)
            {
                sb.AppendLine("\t\tjava.awt.Rectangle source = new java.awt.Rectangle(0, 0, 720, 480);");
                sb.Append("\t\tjava.awt.Rectangle dest = new java.awt.Rectangle(");
                sb.Append(_Screen.ScreenResize.Location.X).Append(", ");
                sb.Append(_Screen.ScreenResize.Location.Y).Append(", ");
                sb.Append(_Screen.ScreenResize.Size.Width).Append(", ");
                sb.Append(_Screen.ScreenResize.Size.Height).AppendLine(");");
                sb.AppendLine("\t\tthis.awtVideoSize = new javax.tv.media.AWTVideoSize(source, dest);");
            }
            else
            {
                sb.AppendLine("\t\tjava.awt.Rectangle source = new java.awt.Rectangle(0, 0, 720, 480);");
                sb.AppendLine("\t\tjava.awt.Rectangle dest = new java.awt.Rectangle(0, 0, 720, 480);");
                sb.AppendLine("\t\tthis.awtVideoSize = new javax.tv.media.AWTVideoSize(source, dest);");
            }

            sb.Append("\n");

            //adding the components.
            foreach (GenericComponentGenerator gcg in _GenericComponentGenerators)
            {
                sb.Append("\t\tthis.add(").Append(gcg.MethodCall).AppendLine(");");
            }

            sb.AppendLine();

            //adding listeners to the buttons.
            foreach (HButtonGenerator hbg in _HButtonGeneratorGenerators)
            {
                sb.Append("\t\tthis.").Append(hbg.MethodCall).AppendLine(".addKeyListener(this.xlet.getListener());");
            }

            sb.AppendLine("\t\tthis.addKeyListener(this.xlet.getListener());");

            sb.AppendLine();

            StringBuilder sbFocusable = new StringBuilder();
            int focusableCount = 0;
            foreach (HButtonGenerator hbg in _HButtonGeneratorGenerators)
            {
                if (hbg.Focusable)
                {
                    sbFocusable.Append("\t\tthis.focusableButtons[").Append(focusableCount).Append("] = ").Append(hbg.MethodCall).AppendLine(";");
                    focusableCount++;
                }
            }

            if (focusableCount > 0)
            {
                sb.Append("\t\tthis.focusableButtons = new org.havi.ui.HIcon[").Append(focusableCount).AppendLine("];");
                sb.AppendLine();
                sb.AppendLine(sbFocusable.ToString());
                sb.AppendLine();
                sb.AppendLine("\t\tthis.focusableButtons[0].requestFocus();");
            }

            sb.AppendLine("\t}");
        }

        private void _LoadKeyEventHandlerMethod(StringBuilder sb, string xletName)
        {
            sb.AppendLine("\tpublic void keyEvent(java.awt.event.KeyEvent event) {");

            int i = 0;

            sb.AppendLine("\t\tswitch(event.getKeyCode()) {");

            //enter
            if (_Screen.HButtons.Count > 0)
            {
                bool firstButtonScreenName = false;

                foreach (HButton hb in _Screen.HButtons)
                {
                    if (hb.ScreenName != null)
                    {
                        string screenStaticVariableName = hb.ScreenName.ToUpper();
                        string value = string.Concat(_Screen.GetProject().NameStartedWithUpperCase, ".", screenStaticVariableName);

                        if (!firstButtonScreenName)
                        {
                            firstButtonScreenName = true;
                            sb.AppendLine("\t\t\tcase java.awt.event.KeyEvent.VK_ENTER: {");
                            sb.Append("\t\t\t\tif (this.count == ").Append(i).AppendLine(") {");
                        }
                        else
                        {
                            sb.Append("\t\t\t\telse if (this.count == ").Append(i).AppendLine(") {");
                        }

                        sb.Append("\t\t\t\t\tthis.xlet.setCurrentScreen(").Append(value).AppendLine(");");
                        sb.AppendLine("\t\t\t\t\tthis.xlet.getCurrentScreen().setLastScreen(this);\n;");
                        sb.AppendLine("\t\t\t\t\treturn;");
                        sb.AppendLine("\t\t\t\t}");
                    }
                    i++;
                }
                if (firstButtonScreenName)
                {
                    sb.AppendLine("\t\t\t\tbreak;");
                    sb.AppendLine("\t\t\t}");
                }
            }

            //special keys
            if (_Screen.ScreenRed != null)
            {
                this._LoadEventEspecial(sb, "KEY_RED", _Screen.ScreenRed, xletName);
            }
            if (_Screen.ScreenGreen != null)
            {
                this._LoadEventEspecial(sb, "KEY_GREEN", _Screen.ScreenGreen, xletName);
            }
            if (_Screen.ScreenYellow != null)
            {
                this._LoadEventEspecial(sb, "KEY_YELLOW", _Screen.ScreenYellow, xletName);
            }
            if (_Screen.ScreenBlue != null)
            {
                this._LoadEventEspecial(sb, "KEY_BLUE", _Screen.ScreenBlue, xletName);
            }

            //verifying if there is more than one focusable elements.
            //in the beggining there are only buttons that are focusable.
            bool focusableElements = false;
            foreach (HButton hb in _Screen.HButtons)
            {
                if (hb.Focusable)
                {
                    focusableElements = true;
                    break;
                }
            }

            if (focusableElements)
            {
                //up
                sb.AppendLine("\t\t\tcase java.awt.event.KeyEvent.VK_UP: {");
                sb.AppendLine("\t\t\t\tif (this.focusableButtons == null) {");
                sb.AppendLine("\t\t\t\t\treturn;");
                sb.AppendLine("\t\t\t\t}");
                sb.AppendLine("\t\t\t\tthis.count--;");
                sb.AppendLine("\t\t\t\tif(this.count < 0) {");
                sb.AppendLine("\t\t\t\t\tthis.count = this.focusableButtons.length-1;");
                sb.AppendLine("\t\t\t\t}");
                sb.AppendLine("\t\t\t\tthis.focusableButtons[ this.count ].requestFocus();");
                sb.AppendLine("\t\t\t\tbreak;");
                sb.AppendLine("\t\t\t}");

                //down
                sb.AppendLine("\t\t\tcase java.awt.event.KeyEvent.VK_DOWN: {");
                sb.AppendLine("\t\t\t\tif (this.focusableButtons == null) {");
                sb.AppendLine("\t\t\t\t\treturn;");
                sb.AppendLine("\t\t\t\t}");
                sb.AppendLine("\t\t\t\tthis.count = (this.count + 1) % this.focusableButtons.length;");
                sb.AppendLine("\t\t\t\tthis.focusableButtons[this.count].requestFocus();");
                sb.AppendLine("\t\t\t\tbreak;");
                sb.AppendLine("\t\t\t}");
            }

            //escape
            sb.AppendLine("\t\t\tcase java.awt.event.KeyEvent.VK_ESCAPE: {");
            sb.AppendLine("\t\t\t\tif (this.lastScreen != null) {");
            sb.AppendLine("\t\t\t\t\tthis.xlet.setCurrentScreen(this.lastScreen);");
            sb.AppendLine("\t\t\t\t}");
            sb.AppendLine("\t\t\t\tbreak;");
            sb.AppendLine("\t\t\t}");

            sb.AppendLine("\t\t}");
            sb.AppendLine("\t}");
        }

        private void _LoadEventEspecial(StringBuilder sb, string key, string screenName, string xletName)
        {
            sb.Append("\t\t\tcase TVDesignerKeyListener.").Append(key).AppendLine("): {");
            sb.Append("\t\t\t\tthis.xlet.setCurrentScreen(").Append(xletName).Append(".").Append(screenName.ToUpper()).AppendLine(");");
            sb.AppendLine("\t\t\t\treturn;");
            sb.AppendLine("\t\t\t}");
        }

        private void _LoadSetXlet(StringBuilder sb, string xletName)
        {
            sb.Append("\tpublic void setXlet(").Append(xletName).AppendLine(" xlet) {");
            sb.AppendLine("\t\tthis.xlet = xlet;");
            sb.AppendLine("\t}");
        }

        private void _LoadSetVisible(StringBuilder sb)
        {
            sb.AppendLine("\tpublic void setVisible(boolean visible) {");
            sb.AppendLine("\t\tsuper.setVisible(visible);");

            sb.AppendLine("\t\tif (this.awtVideoSize != null) {");
            sb.AppendLine("\t\t\tthis.xlet.resize(this.awtVideoSize);");
            sb.AppendLine("\t\t}");

            sb.AppendLine("\t\tthis.requestFocus();");
            sb.AppendLine("\t\tif (this.focusableButtons != null && this.count >= 0 && this.count < this.focusableButtons.length) {");
            sb.AppendLine("\t\t\tthis.focusableButtons[count].requestFocus();");
            sb.AppendLine("\t\t}");
            sb.AppendLine("\t}");
        }
    }
}
